package sg.edu.nus.iss.billing.gui;

import java.awt.BorderLayout;
import java.awt.Color;
import java.awt.Component;
import java.awt.Dimension;
import java.awt.FlowLayout;
import java.awt.Font;
import java.awt.GridBagConstraints;
import java.awt.GridBagLayout;
import java.awt.GridLayout;
import java.awt.Insets;
import java.awt.event.ActionEvent;
import java.awt.event.ActionListener;
import java.awt.event.KeyAdapter;
import java.awt.event.KeyEvent;
import java.io.FileInputStream;
import java.text.DateFormat;
import java.text.SimpleDateFormat;
import java.util.ArrayList;
import java.util.Date;
import java.util.Iterator;
import java.util.List;
import java.util.Properties;

import javax.swing.BorderFactory;
import javax.swing.ButtonGroup;
import javax.swing.ImageIcon;
import javax.swing.JButton;
import javax.swing.JCheckBox;
import javax.swing.JLabel;
import javax.swing.JOptionPane;
import javax.swing.JPanel;
import javax.swing.JRadioButton;
import javax.swing.JTextField;
import javax.swing.SwingConstants;
import javax.swing.border.Border;
import javax.swing.border.CompoundBorder;
import javax.swing.border.EmptyBorder;

import sg.edu.nus.iss.billing.BillingApplication;
import sg.edu.nus.iss.billing.BillingConstants;
import sg.edu.nus.iss.billing.controller.ChargeController;
import sg.edu.nus.iss.billing.controller.CustAccountController;
import sg.edu.nus.iss.billing.exceptions.ControllerException;
import sg.edu.nus.iss.billing.model.account.Account;
import sg.edu.nus.iss.billing.model.account.Account.CustomerStatus;
import sg.edu.nus.iss.billing.model.subscription.AdditionalChannelSubscription;
import sg.edu.nus.iss.billing.model.subscription.CableSubscription;
import sg.edu.nus.iss.billing.model.subscription.CableSubscription.Channels;
import sg.edu.nus.iss.billing.model.subscription.DigitalSubscription;
import sg.edu.nus.iss.billing.model.subscription.ISubscribable;
import sg.edu.nus.iss.billing.model.subscription.MobileSubscription;
import sg.edu.nus.iss.billing.model.subscription.Service;
import sg.edu.nus.iss.billing.model.subscription.Subscription;
import sg.edu.nus.iss.billing.model.user.User.SystemRole;

/**
 * @author Yeo Hee Ling, Ananda, Saravana
 *
 */
public class SubscriptionPanel extends JPanel implements ActionListener {

	private static final long serialVersionUID = 1L;

	private boolean canEdit = true;
	private Properties properties;
	private Account account;
	private BillingApplication billingAppl;
	private DigitalSubscription digitalSubscription;
	private MobileSubscription mobileSubscription;
	private CableSubscription cableSubscription;
	private Service dLocalSvc, dIDDSvc, dCallTransferSvc, mLocalSvc, mIDDSvc, mDataSvc, mRoamingSvc, cStdChnlSvc,
			cAddChnlSvc;
	private int numAdditionalChannels = 0;
	private DateFormat sdf = new SimpleDateFormat("dd-MMM-yyyy");

	private JPanel searchResultPanel;
	private JButton btnAddSubscription, btnSearchResult;

	// Digital Voice Subscription Plan
	private JLabel lblDigitalPlan, lblDigitalIdd, lblDigitalCallTransfer;
	private JRadioButton radDigitalPlanYes, radDigitalPlanNo, radDigitalIddYes, radDigitalIddNo,
			radDigitalCallTransferYes, radDigitalCallTransferNo;
	private JTextField txtDigitalTelNo;

	// Mobile Voice Subscription Plan
	private JLabel lblMobilePlan, lblMobileIdd, lblMobileData, lblMobileRoaming;
	private JRadioButton radMobilePlanYes, radMobilePlanNo, radMobileIddYes, radMobileIddNo, radMobileDataYes,
			radMobileDataNo, radMobileRoamingYes, radMobileRoamingNo;
	private JTextField txtMobileTelNo;

	// Cable TV Subscription Plan
	private JLabel lblCablePlan, lblCableChannels;
	private JRadioButton radCablePlanYes, radCablePlanNo;
	private JCheckBox cbCableChannel1, cbCableChannel2, cbCableChannel3, cbCableChannel4, cbCableChannel5,
			cbCableChannel6, cbCableChannel7;
	private List<JCheckBox> checkboxes;

	public SubscriptionPanel(BillingApplication billingAppl, Account account, JPanel searchResultPanel) {
		this.account = account;
		this.billingAppl = billingAppl;
		this.searchResultPanel = searchResultPanel;
		this.setOpaque(false);

		loadConfiguration();
		if (BillingApplication.getUserSession().getSystemRole() == SystemRole.AGENT
				|| account.getStatus() == CustomerStatus.INACTIVE)
			this.canEdit = false;

		JPanel subscriptionPanel = new JPanel();
		subscriptionPanel.setOpaque(false);
		subscriptionPanel.setLayout(new BorderLayout());
		subscriptionPanel.add(createManageSubscriptionPanel(), BorderLayout.CENTER);

		setSubscriptionRadio("ALL", false);
		loadExistingSubscription();

		add(subscriptionPanel);
	}

	public void actionPerformed(ActionEvent e) {
		if (e.getSource().equals(radDigitalPlanYes)) {
			setSubscriptionRadio(DigitalSubscription.ID, true);
		} else if (e.getSource().equals(radDigitalPlanNo)) {
			setSubscriptionRadio(DigitalSubscription.ID, false);
		} else if (e.getSource().equals(radMobilePlanYes)) {
			setSubscriptionRadio(MobileSubscription.ID, true);
		} else if (e.getSource().equals(radMobilePlanNo)) {
			setSubscriptionRadio(MobileSubscription.ID, false);
		} else if (e.getSource().equals(radCablePlanYes)) {
			setSubscriptionRadio(CableSubscription.ID, true);
		} else if (e.getSource().equals(radCablePlanNo)) {
			setSubscriptionRadio(CableSubscription.ID, false);

		} else if (e.getSource().equals(btnAddSubscription)) {
			boolean isValid;
			try {
				isValid = updateSubscriptionIntoAccount();
			} catch (ControllerException e1) {
				JOptionPane.showMessageDialog(this, e1.getMessage(),
						properties.getProperty("title.manageSubscription"), JOptionPane.ERROR_MESSAGE);
				return;
			}

			if (isValid) {
				try {
					CustAccountController custAccountController = new CustAccountController();
					custAccountController.updateSubscription(account);

					JOptionPane.showMessageDialog(this, properties.getProperty("info.message.updateSuccessfully"),
							properties.getProperty("title.manageSubscription"), JOptionPane.INFORMATION_MESSAGE);

					billingAppl.displayPage(searchResultPanel); // Bring user back to search page.
				} catch (ControllerException ex) {
					JOptionPane.showMessageDialog(this, ex.getMessage(),
							properties.getProperty("title.manageSubscription"), JOptionPane.ERROR_MESSAGE);
					return;
				}
			}
		} else if (e.getSource() == btnSearchResult) {
			billingAppl.displayPage(searchResultPanel);
		}
	}

	private void loadConfiguration() {
		try {
			properties = new Properties();
			FileInputStream in = new FileInputStream(BillingConstants.PROPERTIES_SUBSCRIPTION);
			properties.load(in);
			in.close();
		} catch (Exception ex) {
			ex.printStackTrace();
		}
	}

	private JPanel createManageSubscriptionPanel() {
		JPanel subscriptionPanel = new JPanel();
		subscriptionPanel.setOpaque(false);
		subscriptionPanel.setLayout(new BorderLayout(10, 10));
		subscriptionPanel.add(createHeaderPanel(), BorderLayout.NORTH);
		subscriptionPanel.add(createSubscriptionContentPanel(), BorderLayout.CENTER);
		subscriptionPanel.add(createButtonPanel(), BorderLayout.SOUTH);

		return subscriptionPanel;
	}

	private JPanel createHeaderPanel() {
		// 1. Set the title of the panel.
		String subscriptionPanelTitle = properties.getProperty("title.manageSubscription");

		// 2. Construct the manage subscription panel.
		JPanel headerPanel = new JPanel();
		headerPanel.setOpaque(false);
		headerPanel.setLayout(new GridLayout(0, 1, 10, 10));

		JLabel msgLabel = new JLabel(subscriptionPanelTitle);
		msgLabel.setFont(new Font("Tahoma", Font.BOLD, 18));
		msgLabel.setHorizontalAlignment(SwingConstants.CENTER);
		headerPanel.add(msgLabel);

		ImageIcon imgDivider = new ImageIcon("./images/divider.jpg");
		JLabel lblDivider = new JLabel(imgDivider);
		headerPanel.add(lblDivider);

		// 3. Construct Customer Account information.
		JPanel custAccountInfoPanel = new JPanel();
		custAccountInfoPanel.setOpaque(false);

		JTextField txtCustAccountNo = new JTextField(15);
		txtCustAccountNo.setText(account.getAccountNo());
		txtCustAccountNo.setEditable(false);
		custAccountInfoPanel.add(new JLabel(properties.getProperty("label.subscription.accountNo")));
		custAccountInfoPanel.add(txtCustAccountNo);

		JTextField txtCustomerNric = new JTextField(15);
		txtCustomerNric.setText(account.getCustomerNRIC());
		txtCustomerNric.setEditable(false);
		custAccountInfoPanel.add(new JLabel(properties.getProperty("label.subscription.nric")));
		custAccountInfoPanel.add(txtCustomerNric);

		JTextField txtCustomerName = new JTextField(15);
		txtCustomerName.setText(account.getCustomerName());
		txtCustomerName.setEditable(false);
		custAccountInfoPanel.add(new JLabel(properties.getProperty("label.subscription.name")));
		custAccountInfoPanel.add(txtCustomerName);

		headerPanel.add(custAccountInfoPanel);

		return headerPanel;
	}

	private JPanel createSubscriptionContentPanel() {
		// 1. Construct the Digital Voice Core Panel.
		JPanel subscriptionContentPanel = new JPanel(new GridBagLayout());
		subscriptionContentPanel.setOpaque(false);
		List<Component> cells;

		// header
		cells = new ArrayList<Component>();
		cells.add(new JLabel());
		cells.add(new JLabel(properties.getProperty("header.subscription.current")));
		cells.add(new JLabel(properties.getProperty("header.subscription.change")));
		addRow(subscriptionContentPanel, 0, cells, false);

		// Digital Voice Plan
		cells = new ArrayList<Component>();
		cells.add(new JLabel(properties.getProperty("label.subscription.digitalVoice")));
		cells.add(lblDigitalPlan = new JLabel());
		Object[] returnValues = createRadioButtonGroup(txtDigitalTelNo = new JTextField());
		radDigitalPlanYes = (JRadioButton) returnValues[1];
		radDigitalPlanNo = (JRadioButton) returnValues[2];
		cells.add((JPanel) returnValues[0]);
		txtDigitalTelNo.setPreferredSize(new Dimension(150, 25));
		txtDigitalTelNo.addKeyListener(new KeyAdapter() {
			public void keyTyped(KeyEvent e) {
				if(txtDigitalTelNo.getText().length() >= 8)
					e.consume();
			}
		});
		addRow(subscriptionContentPanel, 1, cells, false);

		// Optional 1: IDD
		cells = new ArrayList<Component>();
		cells.add(new JLabel(properties.getProperty("label.subscription.IDDCalls")));
		cells.add(lblDigitalIdd = new JLabel());
		returnValues = createRadioButtonGroup();
		radDigitalIddYes = (JRadioButton) returnValues[1];
		radDigitalIddNo = (JRadioButton) returnValues[2];
		cells.add((JPanel) returnValues[0]);
		addRow(subscriptionContentPanel, 2, cells, true);

		// Optional 2: Call transfer
		cells = new ArrayList<Component>();
		cells.add(new JLabel(properties.getProperty("label.subscription.callTransfer")));
		cells.add(lblDigitalCallTransfer = new JLabel());
		returnValues = createRadioButtonGroup();
		radDigitalCallTransferYes = (JRadioButton) returnValues[1];
		radDigitalCallTransferNo = (JRadioButton) returnValues[2];
		cells.add((JPanel) returnValues[0]);
		addRow(subscriptionContentPanel, 3, cells, true);

		// Mobile Voice Plan
		cells = new ArrayList<Component>();
		cells.add(new JLabel(properties.getProperty("label.subscription.mobileVoice")));
		cells.add(lblMobilePlan = new JLabel());
		returnValues = createRadioButtonGroup(txtMobileTelNo = new JTextField());
		radMobilePlanYes = (JRadioButton) returnValues[1];
		radMobilePlanNo = (JRadioButton) returnValues[2];
		cells.add((JPanel) returnValues[0]);
		txtMobileTelNo.setPreferredSize(new Dimension(150, 25));
		txtMobileTelNo.addKeyListener(new KeyAdapter() {
			public void keyTyped(KeyEvent e) {
				if(txtMobileTelNo.getText().length() >= 8)
					e.consume();
			}
		});
		addRow(subscriptionContentPanel, 4, cells, false);

		// Optional 1: IDD
		cells = new ArrayList<Component>();
		cells.add(new JLabel(properties.getProperty("label.subscription.IDDCalls")));
		cells.add(lblMobileIdd = new JLabel());
		returnValues = createRadioButtonGroup();
		radMobileIddYes = (JRadioButton) returnValues[1];
		radMobileIddNo = (JRadioButton) returnValues[2];
		cells.add((JPanel) returnValues[0]);
		addRow(subscriptionContentPanel, 5, cells, true);

		// Optional 2: Data service
		cells = new ArrayList<Component>();
		cells.add(new JLabel(properties.getProperty("label.subscription.dataService")));
		cells.add(lblMobileData = new JLabel());
		returnValues = createRadioButtonGroup();
		radMobileDataYes = (JRadioButton) returnValues[1];
		radMobileDataNo = (JRadioButton) returnValues[2];
		cells.add((JPanel) returnValues[0]);
		addRow(subscriptionContentPanel, 6, cells, true);

		// Optional 3: Roaming calls
		cells = new ArrayList<Component>();
		cells.add(new JLabel(properties.getProperty("label.subscription.roaming")));
		cells.add(lblMobileRoaming = new JLabel());
		returnValues = createRadioButtonGroup();
		radMobileRoamingYes = (JRadioButton) returnValues[1];
		radMobileRoamingNo = (JRadioButton) returnValues[2];
		cells.add((JPanel) returnValues[0]);
		addRow(subscriptionContentPanel, 7, cells, true);

		// Cable TV
		cells = new ArrayList<Component>();
		cells.add(new JLabel(properties.getProperty("label.subscription.cableTV")));
		cells.add(lblCablePlan = new JLabel());
		returnValues = createRadioButtonGroup();
		radCablePlanYes = (JRadioButton) returnValues[1];
		radCablePlanNo = (JRadioButton) returnValues[2];
		cells.add((JPanel) returnValues[0]);
		addRow(subscriptionContentPanel, 8, cells, false);

		// Selected Channels
		cells = new ArrayList<Component>();
		cells.add(new JLabel(properties.getProperty("label.subscription.additionalChannel")));
		cells.add(lblCableChannels = new JLabel());
		cells.add(createAdditionalChannelsPanel());
		addRow(subscriptionContentPanel, 9, cells, true);

		return subscriptionContentPanel;
	}

	private void addRow(JPanel panel, int rowNum, List<Component> cells, boolean isOptionalFeature) {
		GridBagConstraints constraints = new GridBagConstraints();
		constraints.fill = GridBagConstraints.BOTH;
		constraints.gridy = rowNum;

		Border border = BorderFactory.createMatteBorder(0, 0, 0, 1, Color.BLACK);
		Border margin;
		if (isOptionalFeature) {
			margin = new EmptyBorder(0, 15, 0, 15);
		} else {
			margin = new EmptyBorder(10, 15, 0, 15);
		}

		int i = 0;
		for (Component cell : cells) {
			if (i == 2 && !this.canEdit) {
				break;
			}

			if (cell instanceof JPanel) {
				((JPanel) cell).setOpaque(false);
				((JPanel) cell).setBorder(new CompoundBorder(border, margin));
			} else if (cell instanceof JLabel) {
				((JLabel) cell).setOpaque(false);
				((JLabel) cell).setBorder(new CompoundBorder(border, margin));
				((JLabel) cell).setVerticalAlignment(SwingConstants.TOP);
			}

			if (i == 0 && isOptionalFeature)
				constraints.insets = new Insets(0, 25, 0, 0);
			else
				constraints.insets = new Insets(0, 0, 0, 0);

			constraints.gridx = i;
			panel.add(cell, constraints);
			i++;
		}

	}

	private Object[] createRadioButtonGroup(Component... extraComponents) {

		JPanel panel = new JPanel(new FlowLayout(FlowLayout.LEFT));
		JRadioButton yesButton = new JRadioButton(properties.getProperty("label.subscription.yes"));
		JRadioButton noButton = new JRadioButton(properties.getProperty("label.subscription.no"));
		yesButton.setOpaque(false);
		noButton.setOpaque(false);

		ButtonGroup group = new ButtonGroup();
		group.add(yesButton);
		group.add(noButton);
		noButton.setSelected(true);

		yesButton.addActionListener(this);
		noButton.addActionListener(this);

		panel.add(yesButton);
		panel.add(noButton);
		for (Component component : extraComponents) {
			if (component != null)
				panel.add(component);
		}

		Object[] returnValues = { panel, yesButton, noButton };
		return returnValues;
	}

	private JPanel createAdditionalChannelsPanel() {
		JPanel panel = new JPanel(new GridLayout(0, 1));

		panel.add(cbCableChannel1 = new JCheckBox(Channels.Channel1.getName()));
		panel.add(cbCableChannel2 = new JCheckBox(Channels.Channel2.getName()));
		panel.add(cbCableChannel3 = new JCheckBox(Channels.Channel3.getName()));
		panel.add(cbCableChannel4 = new JCheckBox(Channels.Channel4.getName()));
		panel.add(cbCableChannel5 = new JCheckBox(Channels.Channel5.getName()));
		panel.add(cbCableChannel6 = new JCheckBox(Channels.Channel6.getName()));
		panel.add(cbCableChannel7 = new JCheckBox(Channels.Channel7.getName()));

		cbCableChannel1.setOpaque(false);
		cbCableChannel2.setOpaque(false);
		cbCableChannel3.setOpaque(false);
		cbCableChannel4.setOpaque(false);
		cbCableChannel5.setOpaque(false);
		cbCableChannel6.setOpaque(false);
		cbCableChannel7.setOpaque(false);

		checkboxes = new ArrayList<JCheckBox>();
		checkboxes.add(cbCableChannel1);
		checkboxes.add(cbCableChannel2);
		checkboxes.add(cbCableChannel3);
		checkboxes.add(cbCableChannel4);
		checkboxes.add(cbCableChannel5);
		checkboxes.add(cbCableChannel6);
		checkboxes.add(cbCableChannel7);

		return panel;
	}

	private JPanel createButtonPanel() {
		JPanel actionBtnPanel = new JPanel();
		actionBtnPanel.setOpaque(false);

		if (BillingApplication.getUserSession().getSystemRole() == SystemRole.ADMIN) {
			if(CustomerStatus.ACTIVE == account.getStatus()) {
				btnAddSubscription = new JButton(properties.getProperty("label.subscription.button.update"));
				btnAddSubscription.setPreferredSize(new Dimension(175, 25));
				btnAddSubscription.addActionListener(this);
				actionBtnPanel.add(btnAddSubscription);
			}
		}

		btnSearchResult = new JButton(properties.getProperty("label.subscription.button.searchResult"));
		btnSearchResult.setPreferredSize(new Dimension(175, 25));
		btnSearchResult.addActionListener(this);
		actionBtnPanel.add(btnSearchResult);

		return actionBtnPanel;
	}

	private void setSubscriptionRadio(String subscriptionPlan, boolean isSelected) {

		if (DigitalSubscription.ID.equals(subscriptionPlan) || "ALL".equals(subscriptionPlan)) {
			radDigitalPlanYes.setSelected(isSelected);
			radDigitalPlanNo.setSelected(!isSelected);
			txtDigitalTelNo.setEditable(isSelected);
			radDigitalIddYes.setEnabled(isSelected);
			radDigitalIddNo.setEnabled(isSelected);
			radDigitalCallTransferYes.setEnabled(isSelected);
			radDigitalCallTransferNo.setEnabled(isSelected);
		}

		if (MobileSubscription.ID.equals(subscriptionPlan) || "ALL".equals(subscriptionPlan)) {
			radMobilePlanYes.setSelected(isSelected);
			radMobilePlanNo.setSelected(!isSelected);
			txtMobileTelNo.setEditable(isSelected);
			radMobileIddYes.setEnabled(isSelected);
			radMobileIddNo.setEnabled(isSelected);
			radMobileDataYes.setEnabled(isSelected);
			radMobileDataNo.setEnabled(isSelected);
			radMobileRoamingYes.setEnabled(isSelected);
			radMobileRoamingNo.setEnabled(isSelected);
		}

		if (CableSubscription.ID.equals(subscriptionPlan) || "ALL".equals(subscriptionPlan)) {
			radCablePlanYes.setSelected(isSelected);
			radCablePlanNo.setSelected(!isSelected);
			cbCableChannel1.setEnabled(isSelected);
			cbCableChannel2.setEnabled(isSelected);
			cbCableChannel3.setEnabled(isSelected);
			cbCableChannel4.setEnabled(isSelected);
			cbCableChannel5.setEnabled(isSelected);
			cbCableChannel6.setEnabled(isSelected);
			cbCableChannel7.setEnabled(isSelected);
		}
	}

	private boolean updateSubscriptionIntoAccount() throws ControllerException {
		List<Subscription> subscriptions = account.getSubscriptions();
		List<Subscription> updatedSubscriptions = new ArrayList<Subscription>();
		for (int n = 0; n < subscriptions.size(); n++) {
			Subscription subscription = subscriptions.get(n);
			if (subscription.getDateTerminated() != null && !"".equals(subscription.getDateTerminated())) {
				if (!subscription.getDateCommenced().equals(sdf.format(new Date())))
					updatedSubscriptions.add(subscription);
			}
		}

		if (updateDigitalVoiceSubscription()) {
			if (digitalSubscription != null)
				updatedSubscriptions.add(digitalSubscription);
		} else {
			return false;
		}

		if (updateMobileVoiceSubscription()) {
			if (mobileSubscription != null)
				updatedSubscriptions.add(mobileSubscription);
		} else {
			return false;
		}

		if (updateCableTVSubscription()) {
			if (cableSubscription != null)
				updatedSubscriptions.add(cableSubscription);
		} else {
			return false;
		}

		account.setSubscriptions(updatedSubscriptions);
		return true;
	}

	private boolean updateDigitalVoiceSubscription() throws ControllerException {
		// 1. Update Subscription for Digital Voice.
		if (radDigitalPlanYes.isSelected()) {
			if (digitalSubscription == null) {
				digitalSubscription = new DigitalSubscription();
				digitalSubscription.setSubscriptionId(DigitalSubscription.ID);
				digitalSubscription.setDateCommenced(sdf.format(new Date()));
			}
			// 1. To remove active service before saving the new service in.
			List<ISubscribable> services = digitalSubscription.getServices();
			List<ISubscribable> updatedServices = new ArrayList<ISubscribable>();
			for (int n = 0; n < services.size(); n++) {
				Service service = (Service) services.get(n);
				if (service.getDateTerminated() != null && !"".equals(service.getDateTerminated())) {
					if (!service.getDateCommenced().equals(sdf.format(new Date())))
						updatedServices.add(service);
				}
			}

			// 2. Validation Checks for Digital Telephone No.
			String digitalTelNo = txtDigitalTelNo.getText().trim();
			if (digitalTelNo != null && !"".equals(digitalTelNo) && isLong(digitalTelNo)) {
				digitalSubscription.setTelephoneNumber(digitalTelNo);
			} else {
				JOptionPane.showMessageDialog(this, properties.getProperty("info.message.invalid.telno"),
						properties.getProperty("title.manageSubscription"), JOptionPane.ERROR_MESSAGE);
				return false;
			}

			if (dLocalSvc == null) {
				dLocalSvc = new Service();
				dLocalSvc.setServiceId(DigitalSubscription.Services.LOCAL.getID());
				dLocalSvc.setDateCommenced(sdf.format(new Date()));
			}
			dLocalSvc.setCharges(ChargeController.getServiceCharges(dLocalSvc));
			updatedServices.add(dLocalSvc);

			if (radDigitalIddYes.isSelected()) {
				if (dIDDSvc == null) {
					dIDDSvc = new Service();
					dIDDSvc.setServiceId(DigitalSubscription.Services.IDD.getID());
					dIDDSvc.setDateCommenced(sdf.format(new Date()));
				}
				dIDDSvc.setCharges(ChargeController.getServiceCharges(dIDDSvc));
				updatedServices.add(dIDDSvc);
			} else {
				if (dIDDSvc != null) {
					dIDDSvc.setServiceId(DigitalSubscription.Services.IDD.getID());
					dIDDSvc.setDateTerminated(sdf.format(new Date()));
					updatedServices.add(dIDDSvc);
				}
			}

			if (radDigitalCallTransferYes.isSelected()) {
				if (dCallTransferSvc == null) {
					dCallTransferSvc = new Service();
					dCallTransferSvc.setServiceId(DigitalSubscription.Services.CALLTRANSFER.getID());
					dCallTransferSvc.setDateCommenced(sdf.format(new Date()));
				}
				dCallTransferSvc.setCharges(ChargeController.getServiceCharges(dCallTransferSvc));
				updatedServices.add(dCallTransferSvc);
			} else {
				if (dCallTransferSvc != null) {
					dCallTransferSvc.setServiceId(DigitalSubscription.Services.CALLTRANSFER.getID());
					dCallTransferSvc.setDateTerminated(sdf.format(new Date()));
					updatedServices.add(dCallTransferSvc);
				}
			}
			digitalSubscription.setServices(updatedServices);

		} else {
			if (digitalSubscription != null) {
				// 1. To remove active service before saving the new service in.
				List<ISubscribable> services = digitalSubscription.getServices();
				List<ISubscribable> updatedServices = new ArrayList<ISubscribable>();
				for (int n = 0; n < services.size(); n++) {
					Service service = (Service) services.get(n);
					if (service.getDateTerminated() != null && !"".equals(service.getDateTerminated())) {
						if (!service.getDateCommenced().equals(sdf.format(new Date())))
							updatedServices.add(service);
					}
				}
				digitalSubscription.setDateTerminated(sdf.format(new Date()));

				if (dLocalSvc != null) {
					dLocalSvc.setServiceId(DigitalSubscription.Services.LOCAL.getID());
					dLocalSvc.setDateTerminated(sdf.format(new Date()));
					updatedServices.add(dLocalSvc);
				}

				if (dIDDSvc != null) {
					dIDDSvc.setServiceId(DigitalSubscription.Services.IDD.getID());
					dIDDSvc.setDateTerminated(sdf.format(new Date()));
					updatedServices.add(dIDDSvc);
				}

				if (dCallTransferSvc != null) {
					dCallTransferSvc.setServiceId(DigitalSubscription.Services.CALLTRANSFER.getID());
					dCallTransferSvc.setDateTerminated(sdf.format(new Date()));
					updatedServices.add(dCallTransferSvc);
				}
				digitalSubscription.setServices(updatedServices);
			}
		}
		return true;
	}

	private boolean updateMobileVoiceSubscription() throws ControllerException {
		if (radMobilePlanYes.isSelected()) {
			if (mobileSubscription == null) {
				mobileSubscription = new MobileSubscription();
				mobileSubscription.setSubscriptionId(MobileSubscription.ID);
				mobileSubscription.setDateCommenced(sdf.format(new Date()));
			}
			// 1. To remove active service before saving the new service in.
			List<ISubscribable> services = mobileSubscription.getServices();
			List<ISubscribable> updatedServices = new ArrayList<ISubscribable>();
			for (int n = 0; n < services.size(); n++) {
				Service service = (Service) services.get(n);
				if (service.getDateTerminated() != null && !"".equals(service.getDateTerminated())) {
					if (!service.getDateCommenced().equals(sdf.format(new Date())))
						updatedServices.add(service);
				}
			}

			// 2. Validation Checks for Digital Telephone No.
			String mobileTelNo = txtMobileTelNo.getText().trim();
			if (mobileTelNo != null && !"".equals(mobileTelNo) && isLong(mobileTelNo)) {
				mobileSubscription.setTelephoneNumber(mobileTelNo);
			} else {
				JOptionPane.showMessageDialog(this, properties.getProperty("info.message.invalid.telno"),
						properties.getProperty("title.manageSubscription"), JOptionPane.ERROR_MESSAGE);
				return false;
			}

			if (mLocalSvc == null) {
				mLocalSvc = new Service();
				mLocalSvc.setServiceId(MobileSubscription.Services.LOCAL.getID());
				mLocalSvc.setDateCommenced(sdf.format(new Date()));
			}
			mLocalSvc.setCharges(ChargeController.getServiceCharges(mLocalSvc));
			updatedServices.add(mLocalSvc);

			if (radMobileIddYes.isSelected()) {
				if (mIDDSvc == null) {
					mIDDSvc = new Service();
					mIDDSvc.setServiceId(MobileSubscription.Services.IDD.getID());
					mIDDSvc.setDateCommenced(sdf.format(new Date()));
				}
				mIDDSvc.setCharges(ChargeController.getServiceCharges(mIDDSvc));
				updatedServices.add(mIDDSvc);
			} else {
				if (mIDDSvc != null) {
					mIDDSvc.setServiceId(MobileSubscription.Services.IDD.getID());
					mIDDSvc.setDateTerminated(sdf.format(new Date()));
					updatedServices.add(mIDDSvc);
				}
			}

			if (radMobileDataYes.isSelected()) {
				if (mDataSvc == null) {
					mDataSvc = new Service();
					mDataSvc.setServiceId(MobileSubscription.Services.DATASERVICE.getID());
					mDataSvc.setDateCommenced(sdf.format(new Date()));
				}
				mDataSvc.setCharges(ChargeController.getServiceCharges(mDataSvc));
				updatedServices.add(mDataSvc);
			} else {
				if (mDataSvc != null) {
					mDataSvc.setServiceId(MobileSubscription.Services.DATASERVICE.getID());
					mDataSvc.setDateTerminated(sdf.format(new Date()));
					updatedServices.add(mDataSvc);
				}
			}

			if (radMobileRoamingYes.isSelected()) {
				if (mRoamingSvc == null) {
					mRoamingSvc = new Service();
					mRoamingSvc.setServiceId(MobileSubscription.Services.ROAMING.getID());
					mRoamingSvc.setDateCommenced(sdf.format(new Date()));
				}
				mRoamingSvc.setCharges(ChargeController.getServiceCharges(mRoamingSvc));
				updatedServices.add(mRoamingSvc);
			} else {
				if (mRoamingSvc != null) {
					mRoamingSvc.setServiceId(MobileSubscription.Services.ROAMING.getID());
					mRoamingSvc.setDateTerminated(sdf.format(new Date()));
					updatedServices.add(mRoamingSvc);
				}
			}
			mobileSubscription.setServices(updatedServices);
		} else {
			if (mobileSubscription != null) {
				// 1. To remove active service before saving the new service in.
				List<ISubscribable> services = mobileSubscription.getServices();
				List<ISubscribable> updatedServices = new ArrayList<ISubscribable>();
				for (int n = 0; n < services.size(); n++) {
					Service service = (Service) services.get(n);
					if (service.getDateTerminated() != null && !"".equals(service.getDateTerminated())) {
						if (!service.getDateCommenced().equals(sdf.format(new Date())))
							updatedServices.add(service);
					}
				}
				mobileSubscription.setDateTerminated(sdf.format(new Date()));

				if (mLocalSvc != null) {
					mLocalSvc.setServiceId(MobileSubscription.Services.LOCAL.getID());
					mLocalSvc.setDateTerminated(sdf.format(new Date()));
					updatedServices.add(mLocalSvc);
				}

				if (mIDDSvc != null) {
					mIDDSvc.setServiceId(MobileSubscription.Services.IDD.getID());
					mIDDSvc.setDateTerminated(sdf.format(new Date()));
					updatedServices.add(mIDDSvc);
				}

				if (mDataSvc != null) {
					mDataSvc.setServiceId(MobileSubscription.Services.DATASERVICE.getID());
					mDataSvc.setDateTerminated(sdf.format(new Date()));
					updatedServices.add(mDataSvc);
				}

				if (mRoamingSvc != null) {
					mRoamingSvc.setServiceId(MobileSubscription.Services.ROAMING.getID());
					mRoamingSvc.setDateTerminated(sdf.format(new Date()));
					updatedServices.add(mRoamingSvc);
				}
				mobileSubscription.setServices(updatedServices);
			}
		}

		return true;
	}

	private boolean updateCableTVSubscription() throws ControllerException {
		if (radCablePlanYes.isSelected()) {
			if (cableSubscription != null) {
				List<AdditionalChannelSubscription> channelList = cableSubscription.getAdditionalChannelNames();
	
				for (JCheckBox checkbox : this.checkboxes) {
					// if the checkbox is currently checked, add a new channel if the channel has no current active
					// subscription
					if (checkbox.isSelected()) {
						boolean hasSubscription = false;
						for (AdditionalChannelSubscription channel : channelList) {
							if (channel.getDateTerminated().equals("")
									&& checkbox.getText().equals(channel.getChannelName())) {
								hasSubscription = true;
								break;
							}
						}
						if (!hasSubscription) {
							channelList.add(new AdditionalChannelSubscription(checkbox.getText(), sdf.format(new Date())));
						}
					}
					// otherwise, terminate the channel if there's an active subscription
					else {
						for (AdditionalChannelSubscription channel : channelList) {
							if (channel.getDateTerminated().equals("")
									&& checkbox.getText().equals(channel.getChannelName())) {
								channel.setDateTerminated(sdf.format(new Date()));
							}
						}
					}
				}
	
				cableSubscription.setAdditionalChannelNames(channelList);
			} else {
				cableSubscription = new CableSubscription();
				cableSubscription.setSubscriptionId(CableSubscription.ID);
				cableSubscription.setDateCommenced(sdf.format(new Date()));
	
				List<AdditionalChannelSubscription> channelList = new ArrayList<AdditionalChannelSubscription>();
				for (JCheckBox checkbox : this.checkboxes) {
					if (checkbox.isSelected()) {
						channelList.add(new AdditionalChannelSubscription(checkbox.getText(), sdf.format(new Date())));
					}
				}
	
				cableSubscription.setAdditionalChannelNames(channelList);
			}
			
			// 1. To remove active service before saving the new service in.
			List<ISubscribable> services = cableSubscription.getServices();
			List<ISubscribable> updatedServices = new ArrayList<ISubscribable>();
			for (int n = 0; n < services.size(); n++) {
				Service service = (Service) services.get(n);
				if (service.getDateTerminated() != null && !"".equals(service.getDateTerminated())) {
					if (!service.getDateCommenced().equals(sdf.format(new Date())))
						updatedServices.add(service);
				}
			}

			if (cStdChnlSvc == null) {
				cStdChnlSvc = new Service();
				cStdChnlSvc.setServiceId(CableSubscription.Services.STANDARDCHANNELS.getID());
				cStdChnlSvc.setDateCommenced(sdf.format(new Date()));
				cStdChnlSvc.setCharges(ChargeController.getServiceCharges(cStdChnlSvc));
				numAdditionalChannels = 0;
			}

			updatedServices.add(cStdChnlSvc);

			cableSubscription.setAdditionalChannels(getNumberOfAdditionalChannel());
			
			//we do update if the number of additional channels changes.
			if (getNumberOfAdditionalChannel() != numAdditionalChannels) {
				if(cAddChnlSvc != null) {
					cAddChnlSvc.setServiceId(CableSubscription.Services.ADDITIONALCHANNELS.getID());
					cAddChnlSvc.setDateTerminated(sdf.format(new Date()));
					updatedServices.add(cAddChnlSvc);
				}
				
				if(getNumberOfAdditionalChannel() > 0) {
					cAddChnlSvc = new Service();
					cAddChnlSvc.setServiceId(CableSubscription.Services.ADDITIONALCHANNELS.getID());
					cAddChnlSvc.setDateCommenced(sdf.format(new Date()));
					
					cAddChnlSvc.clearCharges();
					for (int i = 0; i < getNumberOfAdditionalChannel(); i++) {
						cAddChnlSvc.setCharges(ChargeController.getServiceCharges(cAddChnlSvc));
					}

					updatedServices.add(cAddChnlSvc);
				}
			} 

			cableSubscription.setServices(updatedServices);
		} else {
			if (cableSubscription != null) {
				List<AdditionalChannelSubscription> channelList = cableSubscription.getAdditionalChannelNames();
				for (AdditionalChannelSubscription channel : channelList) {
					channel.setDateTerminated(sdf.format(new Date()));
				}
				cableSubscription.setAdditionalChannelNames(channelList);
				
				// 1. To remove active service before saving the new service in.
				List<ISubscribable> services = cableSubscription.getServices();
				List<ISubscribable> updatedServices = new ArrayList<ISubscribable>();
				for (int n = 0; n < services.size(); n++) {
					Service service = (Service) services.get(n);
					if (service.getDateTerminated() != null && !"".equals(service.getDateTerminated())) {
						if (!service.getDateCommenced().equals(sdf.format(new Date())))
							updatedServices.add(service);
					}
				}
				cableSubscription.setAdditionalChannels(0);
				cableSubscription.setDateTerminated(sdf.format(new Date()));

				if (cStdChnlSvc != null) {
					cStdChnlSvc.setServiceId(CableSubscription.Services.STANDARDCHANNELS.getID());
					cStdChnlSvc.setDateTerminated(sdf.format(new Date()));
					updatedServices.add(cStdChnlSvc);
				}

				if (cAddChnlSvc != null) {
					cAddChnlSvc.setServiceId(CableSubscription.Services.ADDITIONALCHANNELS.getID());
					cAddChnlSvc.setDateTerminated(sdf.format(new Date()));
					updatedServices.add(cAddChnlSvc);
				}

				cableSubscription.setServices(updatedServices);
			}
		}

		return true;
	}

	private void loadExistingSubscription() {
		List<Subscription> subscriptions = account.getSubscriptions();

		lblDigitalPlan.setText("No");
		lblMobilePlan.setText("No");
		lblCablePlan.setText("No");

		Iterator<Subscription> iter = subscriptions.iterator();
		while (iter.hasNext()) {
			Subscription subscription = iter.next();

			if (subscription instanceof DigitalSubscription) {
				DigitalSubscription dSubscription = (DigitalSubscription) subscription;

				if (dSubscription.getDateTerminated() == null || "".equals(dSubscription.getDateTerminated())) {
					digitalSubscription = (DigitalSubscription) subscription;

					setSubscriptionRadio(DigitalSubscription.ID, true);
					lblDigitalPlan.setText("Yes (" + digitalSubscription.getDateCommenced() + ")");
					txtDigitalTelNo.setText(digitalSubscription.getTelephoneNumber() + "");
					lblDigitalIdd.setText("No");
					lblDigitalCallTransfer.setText("No");

					List<ISubscribable> services = digitalSubscription.getServices();
					for (int n = 0; n < services.size(); n++) {
						Service service = (Service) services.get(n);
						if (DigitalSubscription.Services.LOCAL.getID().equals(service.getServiceId())) {
							if (service.getDateTerminated() == null || "".equals(service.getDateTerminated())) {
								dLocalSvc = service;
							}
						} else if (DigitalSubscription.Services.IDD.getID().equals(service.getServiceId())) {
							if (service.getDateTerminated() == null || "".equals(service.getDateTerminated())) {
								dIDDSvc = service;
								radDigitalIddYes.setSelected(true);
								lblDigitalIdd.setText("Yes (" + service.getDateCommenced() + ")");
							}
						} else if (DigitalSubscription.Services.CALLTRANSFER.getID().equals(service.getServiceId())) {
							if (service.getDateTerminated() == null || "".equals(service.getDateTerminated())) {
								dCallTransferSvc = service;
								radDigitalCallTransferYes.setSelected(true);
								lblDigitalCallTransfer.setText("Yes (" + service.getDateCommenced() + ")");
							}
						}
					}
				}
			} else if (subscription instanceof MobileSubscription) {
				MobileSubscription mSubscription = (MobileSubscription) subscription;

				if (mSubscription.getDateTerminated() == null || "".equals(mSubscription.getDateTerminated())) {
					mobileSubscription = (MobileSubscription) subscription;

					setSubscriptionRadio(MobileSubscription.ID, true);
					lblMobilePlan.setText("Yes (" + mobileSubscription.getDateCommenced() + ")");
					txtMobileTelNo.setText(mobileSubscription.getTelephoneNumber() + "");
					lblMobileIdd.setText("No");
					lblMobileData.setText("No");
					lblMobileRoaming.setText("No");

					List<ISubscribable> services = mobileSubscription.getServices();
					for (int n = 0; n < services.size(); n++) {
						Service service = (Service) services.get(n);
						if (MobileSubscription.Services.LOCAL.getID().equals(service.getServiceId())) {
							if (service.getDateTerminated() == null || "".equals(service.getDateTerminated())) {
								mLocalSvc = service;
							}
						} else if (MobileSubscription.Services.IDD.getID().equals(service.getServiceId())) {
							if (service.getDateTerminated() == null || "".equals(service.getDateTerminated())) {
								mIDDSvc = service;
								radMobileIddYes.setSelected(true);
								lblMobileIdd.setText("Yes (" + service.getDateCommenced() + ")");
							}
						} else if (MobileSubscription.Services.DATASERVICE.getID().equals(service.getServiceId())) {
							if (service.getDateTerminated() == null || "".equals(service.getDateTerminated())) {
								mDataSvc = service;
								radMobileDataYes.setSelected(true);
								lblMobileData.setText("Yes (" + service.getDateCommenced() + ")");
							}
						} else if (MobileSubscription.Services.ROAMING.getID().equals(service.getServiceId())) {
							if (service.getDateTerminated() == null || "".equals(service.getDateTerminated())) {
								mRoamingSvc = service;
								radMobileRoamingYes.setSelected(true);
								lblMobileRoaming.setText("Yes (" + service.getDateCommenced() + ")");
							}
						}
					}
				}
			} else if (subscription instanceof CableSubscription) {
				CableSubscription cSubscription = (CableSubscription) subscription;

				if (cSubscription.getDateTerminated() == null || "".equals(cSubscription.getDateTerminated())) {
					cableSubscription = (CableSubscription) subscription;

					setSubscriptionRadio(CableSubscription.ID, true);
					lblCablePlan.setText("Yes (" + cableSubscription.getDateCommenced() + ")");
					lblCableChannels.setText("No");

					List<ISubscribable> services = cableSubscription.getServices();
					for (int n = 0; n < services.size(); n++) {
						Service service = (Service) services.get(n);
						if (CableSubscription.Services.STANDARDCHANNELS.getID().equals(service.getServiceId())) {
							if (service.getDateTerminated() == null || "".equals(service.getDateTerminated())) {
								cStdChnlSvc = service;
							}
						} else if (CableSubscription.Services.ADDITIONALCHANNELS.getID().equals(service.getServiceId())) {
							if (service.getDateTerminated() == null || "".equals(service.getDateTerminated())) {
								cAddChnlSvc = service;

								StringBuilder sb = new StringBuilder();

								List<AdditionalChannelSubscription> channelList = cableSubscription
										.getAdditionalChannelNames();
								for (AdditionalChannelSubscription channel : channelList) {
									if (!channel.getDateTerminated().equals(""))
										continue;

									for (JCheckBox checkbox : this.checkboxes) {
										if (checkbox.getText().equals(channel.getChannelName())) {
											checkbox.setSelected(true);
										}
									}

									sb.append(channel.getChannelName() + " (" + channel.getDateCommenced() + ")<br>");
								}
								lblCableChannels.setText("<html>" + sb.toString() + "</html>");
								numAdditionalChannels = cableSubscription.getAdditionalChannels();
							}
						}
					}

				}
			}
		}
	}

	private int getNumberOfAdditionalChannel() {
		int count = 0;
		for (JCheckBox checkbox : this.checkboxes) {
			if (checkbox.isSelected()) {
				count++;
			}
		}

		return count;
	}

	private boolean isLong(String t) {
		boolean isValidPh = true;

		try {
			Long.parseLong(t);
			if (t.length() < 8)
				isValidPh = false;

		} catch (NumberFormatException ex) {
			isValidPh = false;
		}
		return isValidPh;
	}
}